home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / misc / volume4 / access < prev    next >
Encoding:
Internet Message Format  |  1989-02-03  |  30.4 KB

  1. Path: xanth!mcnc!rutgers!tut.cis.ohio-state.edu!cwjcc!hal!ncoast!allbery
  2. From: george@rebel.UUCP (George M. Sipe)
  3. Newsgroups: comp.sources.misc
  4. Subject: v04i122: extended access control for Unix
  5. Message-ID: <48341@rebel.UUCP>
  6. Date: 11 Oct 88 02:25:39 GMT
  7. Sender: allbery@ncoast.UUCP
  8. Reply-To: george@rebel.UUCP (George M. Sipe)
  9. Organization: Tolerant Systems, Atlanta GA
  10. Lines: 1046
  11. Approved: allbery@ncoast.UUCP
  12.  
  13. Posting-number: Volume 4, Issue 122
  14. Submitted-by: "George M. Sipe" <george@rebel.UUCP>
  15. Archive-name: access
  16.  
  17. [I stand corrected...  (Sorry, Rich, you slowpoke!  ;-)  ++bsa]
  18.  
  19. #! /bin/sh
  20. # This is a shell archive, meaning:
  21. # 1. Remove everything above the #! /bin/sh line.
  22. # 2. Save the resulting text in a file.
  23. # 3. Execute the file with /bin/sh (not csh) to create:
  24. #    README
  25. #    Makefile
  26. #    access.c
  27. #    access.man
  28. # This archive created: Tue Jul 19 13:02:15 1988
  29. export PATH; PATH=/bin:/usr/bin:$PATH
  30. if test -f 'README'
  31. then
  32.     echo shar: "will not over-write existing file 'README'"
  33. else
  34. sed 's/^X//' << \SHAR_EOF > 'README'
  35. XAccess provides a simple yet powerful method of controlling user access
  36. Xto a system.  Simply specify access in place of a login shell in the
  37. Xpassword file for each user who is to have restricted accessibility to
  38. Xa system.  Access will in turn, execute the login shell specified in
  39. Xits argument list if the current tty and time falls within one or more
  40. Xof the access constraints given.
  41. X
  42. XAccessibility constraints limit users by tty port and/or up to 6
  43. Xaccessibility classes of time.
  44. X
  45. XOne of the most valued uses of access is to reserve modem use for UUCP
  46. Xor high priority users.  See the manual page for examples.
  47. X
  48. XBe sure to disable users ability to change their login shell and
  49. Xthereby defeat this control.  For example, "chmod o-x /usr/ucb/chsh".
  50. X
  51. X
  52. X     Copyright (c) 1988 by George M. Sipe.  All rights reserved.
  53. X
  54. XThis software may only be redistributed without fee and without any
  55. Xother form of monetary gain (including sold, rented, leased, or
  56. Xtraded), unless the express written permission of the copyright holder
  57. Xis obtained in advance.
  58. X
  59. XThis copyright notice must be reproduced in its entirety on all copies
  60. Xof this software.  Further, acknowledgment of the authorship of this
  61. Xsoftware must not be removed from its current or derived
  62. Xdocumentation.
  63. X
  64. XNo expressed or implied warranty is made for this software.  No party
  65. Xconnected with this software assumes any liability or responsibility
  66. Xfor its use, the correctness of its operation, or its fitness for any
  67. Xpurpose.
  68. X
  69. XAny distributor of copies of this software shall grant the recipient
  70. Xpermission for further redistribution as permitted by this notice.
  71. X
  72. XPermission is hereby granted to copy, reproduce, redistribute and
  73. Xotherwise use this software as long as the conditions above are
  74. Xstrictly adhered to.
  75. SHAR_EOF
  76. fi
  77. if test -f 'Makefile'
  78. then
  79.     echo shar: "will not over-write existing file 'Makefile'"
  80. else
  81. sed 's/^X//' << \SHAR_EOF > 'Makefile'
  82. X# Makefile for:  access - limit system usage to specified ttys and times
  83. X
  84. XDEFINES        = -DBSD
  85. XCFLAGS        = -O $(DEFINES)
  86. XROFF        = nroff
  87. XRFLAGS        = -man
  88. XLDFLAGS        = -s
  89. XDESTBIN        = ${HOME}
  90. XDESTMAN        = ${HOME}
  91. XDESTCAT        = ${HOME}
  92. XDESTOWN        = root
  93. XDESTGRP        = staff
  94. XSHELL        = /bin/sh
  95. XMAKEFILE    = Makefile
  96. XPROGRAM        = access
  97. XMANPAGES    = access.man
  98. XCATPAGES    = access.cat
  99. XSRCS        = access.c
  100. XOBJS        = access.o
  101. X
  102. X.man.cat:
  103. X        $(ROFF) $(RFLAGS) $< > $@
  104. X
  105. X.SUFFIXES:    .man .cat
  106. X
  107. X# Compile and load the program and format its manual pages.
  108. Xall:        $(PROGRAM) $(CATPAGES)
  109. X
  110. X$(PROGRAM):    $(OBJS)
  111. X        $(CC) $(LDFLAGS) $(OBJS) -o $(PROGRAM)
  112. X
  113. X# Run lint on source files, put results on standard output.
  114. Xlint:
  115. X        lint -u $(DEFINES) $(SRCS)
  116. X
  117. X# Create a tags file for use by a source code editor.
  118. Xtags:        $(SRCS)
  119. X        ctags $(SRCS)
  120. X
  121. X# Edit the makefile and regenerate the dependency information.
  122. Xdepend:
  123. X        mkmf -f $(MAKEFILE) PROGRAM=$(PROGRAM) DESTBIN=$(DESTBIN)
  124. X
  125. X# Print an index of functions on standard output.
  126. Xindex:
  127. X        ctags -wx $(SRCS)
  128. X
  129. X# Print source code files on standard output.
  130. Xprint:
  131. X        lpr -p $(SRCS) $(MANPAGES)
  132. X
  133. X# Compile and load the program, format manual pages, and move them
  134. X# to their destination directories.
  135. Xinstall:    $(PROGRAM) $(CATPAGES)
  136. X        cp $(PROGRAM) $(DESTBIN)
  137. X        chmod 755 $(DESTBIN)/$(PROGRAM)
  138. X        chown $(DESTOWN) $(DESTBIN)/$(PROGRAM)
  139. X        chgrp $(DESTGRP) $(DESTBIN)/$(PROGRAM)
  140. X        -for manpage in $(MANPAGES); do \
  141. X            basepage=`basename $$manpage .man`; \
  142. X            cp $$basepage.man $(DESTMAN)/$$basepage.l; \
  143. X            chmod 644 $(DESTMAN)/$$basepage.l; \
  144. X            chown $(DESTOWN) $(DESTMAN)/$$basepage.l; \
  145. X            chgrp $(DESTGRP) $(DESTMAN)/$$basepage.l; \
  146. X            cp $$basepage.cat $(DESTCAT)/$$basepage.l; \
  147. X            chmod 644 $(DESTCAT)/$$basepage.l; \
  148. X            chown $(DESTOWN) $(DESTCAT)/$$basepage.l; \
  149. X            chgrp $(DESTGRP) $(DESTCAT)/$$basepage.l; \
  150. X        done
  151. X
  152. X# Remove the program and its formatted manual pages from their
  153. X# destination directories.
  154. Xuninstall:
  155. X        rm -f $(DESTBIN)/$(PROGRAM)
  156. X        -for manpage in $(MANPAGES); do \
  157. X            basepage=`basename $$manpage .man`; \
  158. X            rm -f $(DESTMAN)/$$basepage.l; \
  159. X            rm -f $(DESTCAT)/$$basepage.l; \
  160. X        done
  161. X
  162. X# Remove all target and intermediate files.
  163. Xclean:
  164. X        -rm -f $(PROGRAM) $(CATPAGES) $(OBJS)
  165. X        -rm -f core a.out made *.o
  166. SHAR_EOF
  167. fi
  168. if test -f 'access.c'
  169. then
  170.     echo shar: "will not over-write existing file 'access.c'"
  171. else
  172. sed 's/^X//' << \SHAR_EOF > 'access.c'
  173. X/*   Copyright (c) 1988 by George M. Sipe.  All rights reserved.
  174. X
  175. XThis software may only be redistributed without fee and without any
  176. Xother form of monetary gain (including sold, rented, leased, or
  177. Xtraded), unless the express written permission of the copyright holder
  178. Xis obtained in advance.
  179. X
  180. XThis copyright notice must be reproduced in its entirety on all copies
  181. Xof this software.  Further, acknowledgment of the authorship of this
  182. Xsoftware must not be removed from its current or derived
  183. Xdocumentation.
  184. X
  185. XNo expressed or implied warranty is made for this software.  No party
  186. Xconnected with this software assumes any liability or responsibility
  187. Xfor its use, the correctness of its operation, or its fitness for any
  188. Xpurpose.
  189. X
  190. XAny distributor of copies of this software shall grant the recipient
  191. Xpermission for further redistribution as permitted by this notice.
  192. X
  193. XPermission is hereby granted to copy, reproduce, redistribute and
  194. Xotherwise use this software as long as the conditions above are
  195. Xstrictly adhered to.                            */
  196. X
  197. X#include <stdio.h>
  198. X#include <ctype.h>
  199. X#include <pwd.h>
  200. X#include <sys/types.h>
  201. X#ifndef    BSD
  202. X#include <time.h>
  203. X#define    MAXPATHLEN    1024
  204. Xvoid exit();
  205. Xchar *strchr();
  206. Xchar *strrchr();
  207. Xlong time();
  208. X#else
  209. X#include <sys/time.h>
  210. X#include <sys/param.h>
  211. X#undef    MIN
  212. X#define    strchr(s,c)    index(s,c)
  213. X#define    strrchr(s,c)    rindex(s,c)
  214. Xexit();
  215. Xchar *index();
  216. Xchar *rindex();
  217. Xtime_t time();
  218. X#endif
  219. X
  220. Xint execve();
  221. Xint fclose();
  222. Xint fgetc();
  223. Xchar *fgets();
  224. XFILE *fopen();
  225. Xint fputc();
  226. Xint fputs();
  227. Xint geteuid();
  228. Xstruct passwd *getpwuid();
  229. Xstruct tm *localtime();
  230. Xchar *strcat();
  231. Xchar *strcpy();
  232. Xint strlen();
  233. Xint strncmp();
  234. Xchar *ttyname();
  235. Xint ungetc();
  236. X
  237. X/* #define    DEBUG        /* define for tracing information */
  238. X
  239. X#ifndef    TRUE
  240. X#define    TRUE    1        /* true and false */
  241. X#define    FALSE    0
  242. X#endif
  243. X#define    UNSET    3        /* unset flag */
  244. X
  245. X#ifndef    DEBUG
  246. X#define    ACFILE    "/usr/local/lib/access"
  247. X#else
  248. X#define    ACFILE    "test"
  249. X#endif    DEBUG
  250. X#define    MAXENT    1024        /* maximum entry length */
  251. X#define    MAXARGS    99        /* maximum number of arguments in file */
  252. X#define    MAXSH    MAXPATHLEN+7    /* maximum size of SHELL environment variable */
  253. X
  254. X#define    TTY    't'        /* ttyname restrictor */
  255. X#define    MIN    'm'        /* minute restrictor */
  256. X#define    HOUR    'h'        /* hour restrictor */
  257. X#define    WDAY    'w'        /* day of week restrictor */
  258. X#define    MDAY    'D'        /* day of month restrictor */
  259. X#define    MON    'M'        /* month restrictor */
  260. X#define    YEAR    'Y'        /* year restrictor */
  261. X#define    OR    'o'        /* logical or separator */
  262. X#define    PATH    '/'        /* pathname prefix */
  263. X
  264. X#define    ERRNTTY    101        /* not connected to a tty */
  265. X#define    ERRSEP    102        /* missing separator between values */
  266. X#define    ERRRNG1    103        /* '-' appears twice in range */
  267. X#define    ERRRNG2    104        /* '-' does not follow value */
  268. X#define    ERRNUL    105        /* null value */
  269. X#define    ERRMIN    106        /* value below minimum */
  270. X#define    ERRMAX    107        /* value exceeds maximum */
  271. X#define    ERRBAD    108        /* invalid character */
  272. X
  273. Xtypedef    char BOOL;
  274. X
  275. Xstatic struct tm *timenow;    /* the current local time */
  276. Xstatic char *name = NULL;    /* pointer to username */
  277. Xstatic int namesz;        /* size of username */
  278. Xstatic char *ttynm = NULL;    /* pointer to ttyname */
  279. Xstatic int ttysz;        /* size of ttyname */
  280. X
  281. Xstatic BOOL user;        /* TRUE or FALSE */
  282. Xstatic BOOL tty;        /* UNSET, TRUE, or FALSE */
  283. Xstatic BOOL min[60];        /* 0 to 59 */
  284. Xstatic BOOL hour[24];        /* 0 to 23 */
  285. Xstatic BOOL wday[8];        /* 0 (Sunday) to 6 (Saturday);  7 = 0 too */
  286. Xstatic BOOL mday[32];        /* 1 to 31 */
  287. Xstatic BOOL mon[13];        /* 1 to 12 */
  288. Xstatic BOOL year[99];        /* 87 to 99 */
  289. X
  290. X/* Display userchk(), ttychk(), and expand() error message. */
  291. X
  292. Xstatic void error(type, string, code)
  293. Xchar *type;
  294. Xchar *string;
  295. Xint code;
  296. X{
  297. X    fputs("\n*** system access processing failure - ", stderr);
  298. X    fputs("report to your system manager ***\n\n", stderr);
  299. X
  300. X    if (code == 0) {
  301. X        fputs(type, stderr);
  302. X        fputs(string, stderr);
  303. X        fputc('\n', stderr);
  304. X        exit(0);
  305. X    }
  306. X
  307. X    fputs("invalid ", stderr);
  308. X    fputs(type, stderr);
  309. X    fputs(" specification:  '", stderr);
  310. X    fputs(string, stderr);
  311. X    fputs("'  ", stderr);
  312. X    switch (code) {
  313. X        case ERRNTTY:
  314. X            fputs("(not connected to a tty)\n", stderr);
  315. X            break;
  316. X        case ERRSEP:
  317. X            fputs("(missing separator between values)\n", stderr);
  318. X            break;
  319. X        case ERRRNG1:
  320. X            fputs("('-' appears twice in range)\n", stderr);
  321. X            break;
  322. X        case ERRRNG2:
  323. X            fputs("('-' does not follow value)\n", stderr);
  324. X            break;
  325. X        case ERRNUL:
  326. X            fputs("(null value)\n", stderr);
  327. X            break;
  328. X        case ERRMIN:
  329. X            fputs("(value below minimum)\n", stderr);
  330. X            break;
  331. X        case ERRMAX:
  332. X            fputs("(value exceeds maximum)\n", stderr);
  333. X            break;
  334. X        case ERRBAD:
  335. X            fputs("(invalid character)\n", stderr);
  336. X            break;
  337. X        default:
  338. X            fputs("(indeterminant error)\n", stderr);
  339. X            break;
  340. X    }
  341. X    exit(0);
  342. X}
  343. X
  344. X/* Given a string containing usernames, check them against the current
  345. X   user's name.  If there is a match, set the global 'user' to TRUE
  346. X   otherwise set 'user' to FALSE.  In addition to a direct match, 'user'
  347. X   may be set to TRUE by '*'.  Further, '!' may be used to negate its
  348. X   meaning.  Return FALSE if no errors, error number otherwise.
  349. X*/
  350. X
  351. Xstatic int userchk(string)
  352. Xchar *string;
  353. X{
  354. X    register char *cp, *s1;
  355. X    register BOOL seen = FALSE;
  356. X    register BOOL negate = FALSE;
  357. X    struct passwd *passwd;
  358. X
  359. X    if (!name) {
  360. X        if (!(passwd = getpwuid(geteuid())))
  361. X            error("could not access passwd entry", "", 0);
  362. X        name = passwd->pw_name;
  363. X        namesz = strlen(name);
  364. X#ifdef    DEBUG
  365. X        fputs("My username is:  ", stderr);
  366. X        fputs(name, stderr);
  367. X        fputs("\n", stderr);
  368. X#endif    DEBUG
  369. X    }
  370. X    user = FALSE;
  371. X    for (cp = string; ; ) switch (*cp) {
  372. X        case ' ':    /* whitespace terminates immediately */
  373. X        case '\t':
  374. X        case '#':
  375. X        case '\n':
  376. X            return (FALSE);
  377. X        case '!':    /* negation requested */
  378. X        case '^':
  379. X            /* be sure nothing yet specified */
  380. X            if (seen) return (ERRSEP);
  381. X            negate = !negate;
  382. X            ++cp;
  383. X            break;
  384. X        case '*':    /* every username */
  385. X        case '@':
  386. X            /* be sure nothing yet specified */
  387. X            if (seen) return (ERRSEP);
  388. X            seen = TRUE;
  389. X            user = !negate;
  390. X            ++cp;
  391. X            break;
  392. X        case '\000':    /* string/specification end */
  393. X        case ',':    /* specification end */
  394. X            /* be sure value was found */
  395. X            if (!seen) return (ERRNUL);
  396. X            if (!*cp) return (FALSE);
  397. X            seen = FALSE;
  398. X            negate = FALSE;
  399. X            ++cp;
  400. X            break;
  401. X        default:    /* user specification found */
  402. X            /* be sure nothing yet specified */
  403. X            if (seen) return (ERRSEP);
  404. X            seen = TRUE;
  405. X            s1 = cp;
  406. X            /* find the end of the specification */
  407. X            while (*cp && !strchr(" \t#\n!^*@,", *cp)) ++cp;
  408. X            /* see if it doesn't match by definition */
  409. X            if ((cp - s1) != namesz) break;
  410. X            /* see if it doesn't match */
  411. X            if (strncmp(name, s1, namesz)) break;
  412. X            user = !negate;
  413. X            break;
  414. X    }
  415. X}
  416. X
  417. X/* Given a string containing the trailing portion of a ttyname, check
  418. X   it against the current tty's name.  If it matches, set the global
  419. X   'tty' to TRUE.  The first time ttychk() is called within an overall
  420. X   specification, 'tty' is set to FALSE.  It may be set to TRUE by '*'
  421. X   at any time.  Further, '!' may be used to negate its meaning.  Return
  422. X   FALSE if no errors, error number otherwise.
  423. X*/
  424. X
  425. Xstatic int ttychk(string)
  426. Xchar *string;
  427. X{
  428. X    register char *cp, *s1, *s2;
  429. X    register BOOL seen = FALSE;
  430. X    register BOOL negate = FALSE;
  431. X
  432. X    if (!ttynm) {
  433. X        if (!(ttynm = ttyname(0))) return (ERRNTTY);
  434. X        ttysz = strlen(ttynm);
  435. X#ifdef    DEBUG
  436. X        fputs("My ttyname is:  ", stderr);
  437. X        fputs(ttynm, stderr);
  438. X        fputs("\n", stderr);
  439. X#endif    DEBUG
  440. X    }
  441. X    if (tty == UNSET) tty = FALSE;
  442. X    cp = string + 1;            /* skip first byte */
  443. X    for (;;) switch (*cp) {
  444. X        case ' ':    /* skip whitespace */
  445. X        case '\t':
  446. X            ++cp;
  447. X            break;
  448. X        case '!':    /* negation requested */
  449. X        case '^':
  450. X            /* be sure nothing yet specified */
  451. X            if (seen) return (ERRSEP);
  452. X            negate = !negate;
  453. X            ++cp;
  454. X            break;
  455. X        case '*':    /* every ttyname */
  456. X        case '@':
  457. X            /* be sure nothing yet specified */
  458. X            if (seen) return (ERRSEP);
  459. X            seen = TRUE;
  460. X            tty = !negate;
  461. X            ++cp;
  462. X            break;
  463. X        case '\000':    /* string/specification end */
  464. X        case ',':    /* specification end */
  465. X            /* be sure value was found */
  466. X            if (!seen) return (ERRNUL);
  467. X            if (!*cp) return (FALSE);
  468. X            seen = FALSE;
  469. X            negate = FALSE;
  470. X            ++cp;
  471. X            break;
  472. X        case '-':    /* '-' does not follow value */
  473. X            return (ERRRNG2);
  474. X        default:    /* tty specification found */
  475. X            /* be sure nothing yet specified */
  476. X            if (seen) return (ERRSEP);
  477. X            seen = TRUE;
  478. X            s1 = cp;
  479. X            /* find the end of the specification */
  480. X            while (*cp && !strchr(" \t!^*@,-", *cp)) ++cp;
  481. X            s2 = ttynm + ttysz - (cp - s1);
  482. X            /* see if it doesn't match by definition */
  483. X            if (s2 < ttynm) break;
  484. X            /* check for simple non-range specification */
  485. X            if (*cp != '-') {
  486. X                /* see if it doesn't match */
  487. X                if (strncmp(s2, s1, cp - s1)) break;
  488. X                tty = !negate;
  489. X                break;
  490. X            }
  491. X            /* see if < start of range */
  492. X            if (strncmp(s2, s1, cp - s1) < 0) {
  493. X                /* it is, skip past range limit */
  494. X                ++cp;
  495. X                while (*cp && !strchr(" \t!^*@,-", *cp)) ++cp;
  496. X                if (*cp == '-') return (ERRRNG1);
  497. X                break;
  498. X            }
  499. X            /* find the start and end of range limit */
  500. X            s1 = ++cp;
  501. X            while (*cp && !strchr(" \t!^*@,-", *cp)) ++cp;
  502. X            if (*cp == '-') return (ERRRNG1);
  503. X            s2 = ttynm + ttysz - (cp - s1);
  504. X            /* see if it doesn't match by definition */
  505. X            if (s2 < ttynm) break;
  506. X            /* see if > end of range */
  507. X            if (strncmp(s2, s1, cp - s1) > 0) break;
  508. X            tty = !negate;
  509. X            break;
  510. X    }
  511. X}
  512. X
  513. X/* Extract a positive, integer value from the string pointed to by
  514. X   'cp' into the int pointed to by 'pnum'.  Return the first non-digit
  515. X   position in 'cp'.
  516. X*/
  517. X
  518. Xstatic char *getnum(cp, pnum)
  519. Xchar *cp;
  520. Xint *pnum;
  521. X{
  522. X    register int num = 0;
  523. X
  524. X    while (isdigit(*cp)) num = num * 10 + (*cp++ - '0');
  525. X    *pnum = num;
  526. X    return (cp);
  527. X}
  528. X
  529. X/* Given a string containing numeric values and ranges separated by
  530. X   commas - generate a truth vector between 0 and 'max'-1 for those
  531. X   values which are specified.  Example:  "2,4,6-10,14".  The first
  532. X   time expand() is called for a given vector, all values are set to
  533. X   FALSE.  Thereafter, new values are added to the existing vector.
  534. X   Note:  any single number or range may be preceeded by '!' to negate
  535. X   its meaning (set the specified values to FALSE).  An example might
  536. X   be "*,!9-17".  Further note:  the first byte of the specified string
  537. X   is ignored.  Return FALSE if no errors, error number otherwise.
  538. X*/
  539. X
  540. Xstatic int expand(string, vector, minimum, maximum)
  541. Xchar *string;
  542. XBOOL vector[];
  543. Xint minimum, maximum;
  544. X{
  545. X    register char *cp;
  546. X    register int i;
  547. X    register int range = -1;
  548. X    register BOOL negate = FALSE;
  549. X    int num = -1;
  550. X
  551. X    if (vector[0] == UNSET)
  552. X        for (i = 0; i <= maximum; ++i) vector[i] = FALSE;
  553. X    cp = string + 1;    /* skip first byte */
  554. X    for (;;) switch (*cp) {
  555. X        case ' ':    /* skip whitespace */
  556. X        case '\t':
  557. X            ++cp;
  558. X            break;
  559. X        case '!':    /* negation requested */
  560. X        case '^':
  561. X            /* be sure value is new */
  562. X            if (num >= 0) return (ERRSEP);
  563. X            negate = !negate;
  564. X            ++cp;
  565. X            break;
  566. X        case '*':    /* full range */
  567. X        case '@':
  568. X            /* be sure value is new */
  569. X            if (num >= 0) return (ERRSEP);
  570. X            /* check for range started */
  571. X            if (range >= 0) {
  572. X                num = maximum;
  573. X                ++cp;
  574. X                break;
  575. X            }
  576. X            /* no range yet */
  577. X            ++cp;
  578. X            while (*cp == ' ' || *cp == '\t') ++cp;
  579. X            /* check for range continued */
  580. X            if (*cp == '-') {
  581. X                num = minimum;
  582. X            } else {
  583. X                range = minimum;
  584. X                num = maximum;
  585. X            }
  586. X            break;
  587. X        case '0':    /* value found */
  588. X        case '1':
  589. X        case '2':
  590. X        case '3':
  591. X        case '4':
  592. X        case '5':
  593. X        case '6':
  594. X        case '7':
  595. X        case '8':
  596. X        case '9':
  597. X            /* be sure value is new */
  598. X            if (num >= 0) return (ERRSEP);
  599. X            cp = getnum(cp, &num);
  600. X            break;
  601. X        case '-':    /* range specified */
  602. X            /* be sure range is new */
  603. X            if (range >= 0) return (ERRRNG1);
  604. X            /* be sure value was found */
  605. X            if (num < 0) return (ERRRNG2);
  606. X            range = num;    /* save first value */
  607. X            num = -1;
  608. X            ++cp;
  609. X            break;
  610. X        case '\000':    /* string/specification end */
  611. X        case ',':    /* specification end */
  612. X            /* be sure value was found */
  613. X            if (num < 0) return (ERRNUL);
  614. X            /* range of one if not specified */
  615. X            if (range < 0) range = num;
  616. X            /* set range as increasing if needed */
  617. X            if (range > num) {
  618. X                i = num;
  619. X                num = range;
  620. X                range = i;
  621. X            }
  622. X            /* check against minimum */
  623. X            if (num < minimum) return (ERRMIN);
  624. X            /* check against maximum */
  625. X            if (range > maximum) return (ERRMAX);
  626. X            /* update truth vector */
  627. X            for (i = range; i <= num; ++i)
  628. X                vector[i] = !negate;
  629. X            negate = FALSE;
  630. X            /* specification done */
  631. X            num = range = -1;
  632. X            if (!*cp) return (FALSE);
  633. X            ++cp;
  634. X            break;
  635. X        default:
  636. X            return (ERRBAD);
  637. X    }
  638. X}
  639. X
  640. X#ifdef    DEBUG
  641. X
  642. X/* Display the specified string followed by a dump of the specified
  643. X   truth vector.
  644. X*/
  645. X
  646. Xstatic void dump(string, vector, minimum, maximum)
  647. Xchar *string;
  648. XBOOL vector[];
  649. Xint minimum, maximum;
  650. X{
  651. X    register int i;
  652. X
  653. X    if (vector[0] == UNSET) return;
  654. X    fputs(string, stderr);
  655. X    for (i = minimum; i <= maximum; ++i)
  656. X        if (vector[i])
  657. X            fputc('T', stderr);
  658. X        else
  659. X            fputc('-', stderr);
  660. X    fputc('\n', stderr);
  661. X}
  662. X
  663. X#endif    DEBUG
  664. X
  665. X/* Evaluate a specific series of time specifications relative to the
  666. X   current time.  Return TRUE if current time is within them.  Update
  667. X   count to reflect the number of specs processed.
  668. X*/
  669. X
  670. Xstatic BOOL within(specs, count)
  671. Xchar **specs;
  672. Xint *count;
  673. X{
  674. X    register int i, code;
  675. X
  676. X    tty = UNSET;
  677. X    for (i = 0; i < 60; ++i) min[i]  = UNSET;
  678. X    for (i = 0; i < 24; ++i) hour[i] = UNSET;
  679. X    for (i = 0; i < 32; ++i) mday[i] = UNSET;
  680. X    for (i = 0; i < 13; ++i) mon[i]  = UNSET;
  681. X    for (i = 0; i < 99; ++i) year[i] = UNSET;
  682. X    for (i = 0; i <  8; ++i) wday[i] = UNSET;
  683. X    *count = 0;
  684. X    if (**specs == '-') ++*specs;
  685. X    do {
  686. X#ifdef    DEBUG
  687. X        fputs("processing specification:  ", stderr);
  688. X        fputs(*specs, stderr);
  689. X        fputc('\n', stderr);
  690. X#endif    DEBUG
  691. X        switch (**specs) {
  692. X            case TTY:
  693. X                if (code = ttychk(*specs))
  694. X                    error("tty", *specs, code);
  695. X                break;
  696. X            case MIN:
  697. X                if (code = expand(*specs, min, 0, 59))
  698. X                    error("minute", *specs, code);
  699. X                break;
  700. X            case HOUR:
  701. X                if (code = expand(*specs, hour, 0, 23))
  702. X                    error("hour", *specs, code);
  703. X                break;
  704. X            case MDAY:
  705. X                if (code = expand(*specs, mday, 1, 31))
  706. X                    error("day of month", *specs, code);
  707. X                break;
  708. X            case MON:
  709. X                if (code = expand(*specs, mon, 1, 12))
  710. X                    error("month", *specs, code);
  711. X                break;
  712. X            case YEAR:
  713. X                if (code = expand(*specs, year, 87, 99))
  714. X                    error("year", *specs, code);
  715. X                break;
  716. X            case WDAY:
  717. X                if (code = expand(*specs, wday, 0, 7))
  718. X                    error("day of week", *specs, code);
  719. X                if (wday[0] || wday[7])
  720. X                    wday[0] = wday[7] = TRUE;
  721. X                break;
  722. X            default:
  723. X                error("invalid specification:  ", *specs, 0);
  724. X        }
  725. X        ++specs;
  726. X        ++*count;
  727. X        if (**specs == '-') ++*specs;
  728. X    } while (**specs != OR && **specs != PATH);
  729. X    if (**specs == OR) {
  730. X        if (*(*specs+1) && (*(*specs+1) != 'r' || *(*specs+2)))
  731. X            error("invalid specification:  ", *specs, 0);
  732. X        ++*count;
  733. X    }
  734. X
  735. X#ifdef    DEBUG
  736. X    fputs("acceptible restrictions are...\n", stderr);
  737. X    dump("  minutes:        ", min, 0, 59);
  738. X    dump("  hours:          ", hour, 0, 23);
  739. X    dump("  days of week:   ", wday, 0, 6);
  740. X    dump("  days of month:  ", mday, 1, 31);
  741. X    dump("  months:         ", mon, 1, 12);
  742. X    dump("  years:          ", year, 87, 99);
  743. X    if (tty != UNSET) {
  744. X        fputs("(also no restriction on tty '", stderr);
  745. X        fputs(ttynm, stderr);
  746. X        if (tty) fputs("' - PASSED)\n", stderr);
  747. X        else fputs("' - FAILED)\n", stderr);
  748. X    }
  749. X    fputc('\n', stderr);
  750. X#endif    DEBUG
  751. X
  752. X    return (tty && min[timenow->tm_min] && hour[timenow->tm_hour] &&
  753. X        wday[timenow->tm_wday] && mday[timenow->tm_mday] &&
  754. X        mon[timenow->tm_mon] && year[timenow->tm_year]);
  755. X}
  756. X
  757. Xvoid main(argc, argv, environ)
  758. Xint argc;
  759. Xchar **argv, *environ[];
  760. X{
  761. X    register int i;
  762. X    register BOOL runable = FALSE;
  763. X    register char *cp;
  764. X    BOOL testing = **argv != '-';
  765. X    int count;
  766. X    time_t clock;
  767. X    FILE *acfp;
  768. X    char buf[MAXENT];
  769. X    char *fargv[MAXARGS];
  770. X    char shell[MAXSH];
  771. X
  772. X    (void) time(&clock);
  773. X    timenow = localtime(&clock);
  774. X    ++(timenow->tm_mon);
  775. X
  776. X#ifdef    DEBUG
  777. X    min[timenow->tm_min] = TRUE;
  778. X    hour[timenow->tm_hour] = TRUE;
  779. X    wday[timenow->tm_wday] = TRUE;
  780. X    mday[timenow->tm_mday] = TRUE;
  781. X    mon[timenow->tm_mon] = TRUE;
  782. X    year[timenow->tm_year] = TRUE;
  783. X
  784. X    fputs("time now is...\n", stderr);
  785. X    dump("  minute:         ", min, 0, 59);
  786. X    dump("  hour:           ", hour, 0, 23);
  787. X    dump("  day of week:    ", wday, 0, 6);
  788. X    dump("  day of month:   ", mday, 1, 31);
  789. X    dump("  month:          ", mon, 1, 12);
  790. X    dump("  year:           ", year, 87, 99);
  791. X    fputc('\n', stderr);
  792. X#endif    DEBUG
  793. X
  794. X    if (argc < 2) {
  795. X        if (!(acfp = fopen(ACFILE, "r")))
  796. X            error("could not open control file:  ", ACFILE, 0);
  797. X        /* find this user's entry in the control file */
  798. X        while (!user && fgets(buf, MAXENT, acfp))
  799. X            if (i = userchk(buf)) {
  800. X                for (cp = buf; *cp && !strchr(" \t#\n", *cp);
  801. X                    ++cp) ;
  802. X                *cp = '\000';
  803. X                error("user", buf, i);
  804. X            }
  805. X        if (!user) error(name, " not in control file", 0);
  806. X        /* find the end of the first line */
  807. X        for (cp = buf; *cp && !strchr("#\n", *cp); ++cp) ;
  808. X        *cp = '\000';
  809. X        /* append continuation lines */
  810. X        while (count = MAXENT - (cp - buf)) {
  811. X            i = fgetc(acfp);
  812. X            if (!strchr(" \t#\n", i)) break;
  813. X            (void) ungetc(i, acfp);
  814. X            if (!fgets(cp, count, acfp)) break;
  815. X            while (*cp && !strchr("#\n", *cp)) ++cp;
  816. X            *cp = '\000';
  817. X        }
  818. X        (void) fclose(acfp);
  819. X#ifdef    DEBUG
  820. X        fputs("control entry:  ", stderr);
  821. X        fputs(buf, stderr);
  822. X        fputc('\n', stderr);
  823. X#endif    DEBUG
  824. X        argc = 0;
  825. X        argv = fargv;
  826. X        argv[argc++] = cp = buf;
  827. X        /* process arguments */
  828. X        while (*cp) {
  829. X            /* scan past last argument */
  830. X            while (*cp && *cp != ' ' && *cp != '\t') ++cp;
  831. X            /* terminate it with null */
  832. X            if (*cp) *cp++ = '\000';
  833. X            /* find the next argument */
  834. X            while (*cp && (*cp == ' ' || *cp == '\t')) ++cp;
  835. X            if (*cp) {
  836. X                /* found one, enter it into argv */
  837. X                if (argc == MAXARGS)
  838. X                    error("too many arguments ",
  839. X                        "in control file", 0);
  840. X                argv[argc++] = cp;
  841. X            }
  842. X        }
  843. X        argv[argc] = NULL;
  844. X#ifdef    DEBUG
  845. X        for (i = 1; i < argc; ++i) {
  846. X            fputs("found specification:  ", stderr);
  847. X            fputs(argv[i], stderr);
  848. X            fputs("\n", stderr);
  849. X        }
  850. X        fputs("\n", stderr);
  851. X#endif    DEBUG
  852. X    }
  853. X
  854. X    for (i = 1; i < argc; ++i) if (*argv[i] == PATH) break;
  855. X    if (i == argc)
  856. X        error("full pathname to exec() required", "", 0);
  857. X
  858. X    if (**(++argv) == PATH) runable = TRUE;
  859. X    else do {
  860. X        runable |= within(argv, &count);
  861. X        argv += count;
  862. X    } while (**argv != PATH);
  863. X
  864. X    if (runable) {
  865. X#ifdef    DEBUG
  866. X        fputs("\ntime and tty IS within specifications\n", stderr);
  867. X#endif    DEBUG
  868. X        /* set the shell buffer to be "SHELL=pathname" */
  869. X        (void) strcpy(shell, "SHELL=");
  870. X        (void) strcat(shell, *argv);
  871. X        /* fix argv[0] to point to '-progname' */
  872. X        if (cp = strrchr(*argv, '/')) {
  873. X            *cp = '-';
  874. X            (void) strcpy(*argv, cp);
  875. X        }
  876. X        /* set cp to point to the pathname to execute */
  877. X        cp = shell + 6;
  878. X        /* find and fix the SHELL environment variable */
  879. X        for (i = 0; environ[i]; ++i) {
  880. X            if (!strncmp(environ[i], "SHELL=", 6)) {
  881. X                environ[i] = shell;
  882. X                break;
  883. X            }
  884. X        }
  885. X        if (testing) {
  886. X            fputs(cp, stderr);
  887. X            fputs(": ", stderr);
  888. X            for (i = 0; argv[i]; ++i) {
  889. X                fputs(" \"", stderr);
  890. X                fputs(argv[i], stderr);
  891. X                fputc('"', stderr);
  892. X            }
  893. X            fputc('\n', stderr);
  894. X            exit(0);
  895. X        }
  896. X        (void) execve(cp, argv, environ);
  897. X        error("could not exec() ", cp, 0);
  898. X    } else {
  899. X#ifdef    DEBUG
  900. X        fputs("\ntime or tty is NOT within specifications\n", stderr);
  901. X#endif    DEBUG
  902. X        fputs("\n*** your access ", stderr);
  903. X        if (ttynm) fputs("(on this tty port) ", stderr);
  904. X        fputs("is not permitted at this time ***\n", stderr);
  905. X    }
  906. X}
  907. SHAR_EOF
  908. fi
  909. if test -f 'access.man'
  910. then
  911.     echo shar: "will not over-write existing file 'access.man'"
  912. else
  913. sed 's/^X//' << \SHAR_EOF > 'access.man'
  914. X.TH ACCESS l "19 June 1988"
  915. X.SH NAME
  916. Xaccess \- limit system usage to specified ttys and times
  917. X.SH SYNTAX
  918. X.B "/usr/local/etc/access"
  919. X.SH DESCRIPTION
  920. X.I Access
  921. Xprovides a simple yet powerful method of limiting user access to a
  922. Xsystem.  Simply specify
  923. X.B /usr/local/etc/access
  924. Xin place of a login shell in the password file for each user who is to
  925. Xhave restricted accessibility to a system.
  926. X.I Access
  927. Xwill lookup that user's entry in the control file
  928. X.B /usr/local/lib/access
  929. Xand execute the specified real login shell (with optional arguments) if
  930. Xthe current tty and time falls within one or more of the access
  931. Xconstraints given.
  932. X.PP
  933. XEach entry in the control file has the form:
  934. X.PP
  935. Xuserspec [constraint1] [...[-]o[r] constraintN]
  936. X.br
  937. X    full_pathname [args]
  938. X.PP
  939. XBlank lines are ignored, while `#' marks the start of a comment which
  940. Xcontinues to the end of the line.  Entries may be continued by indenting
  941. Xcontinuation lines with whitespace (blanks or tabs).  Entries are
  942. Xlimited to a maximum of 1k characters.
  943. X.PP
  944. XAccessibility constraints limit the tty port and/or up to 6
  945. Xaccessibility classes of time.  Accessibility constraints are composed
  946. Xof multiple specifications separated by spaces and/or tabs.  Additional
  947. Xconstraints may be specified by connecting them with the
  948. X.B OR
  949. Xoperator (see below).
  950. X.PP
  951. XEach specification within an accessibility constraint is composed of a
  952. Xletter (optionally preceded by `-') followed by the specification.  They
  953. Xare as follows:
  954. X.PP
  955. X.nf
  956. X.ta 0.8i 1.6i 2.4i
  957. X    class    range    description
  958. X    -----    -----    -----------
  959. X    `t'        tty name restrictor
  960. X    `m'    0-59    minute restrictor
  961. X    `h'    0-23    hour restrictor
  962. X    `w'    0-6    day of week restrictor (0 = Sunday)
  963. X    `D'    1-31    day of month restrictor
  964. X    `M'    1-12    month restrictor
  965. X    `Y'    87-99    year restrictor
  966. X    `o[r]'        logical OR separator
  967. X.fi
  968. X.PP
  969. XWhere an accessibility class is not specified within an accessibility
  970. Xconstraint, no restriction will be applied to that class.  For instance,
  971. Xif `m' does not appear within an accessibility constraint then
  972. Xaccessibility will not be constrained by the current minute.
  973. X.PP
  974. XNumeric accessibility classes are specified with single values or a
  975. Xrange of values separated by `-'.  Multiple specifications may be given
  976. Xat one time separated by `,'.  Any given class may appear more than
  977. Xonce.  The sense of any specific specification may be negated by `!'
  978. X(or `^').  Further, `*' (or `@') may be used to indicate infinity.  For
  979. Xexample, each of the following are equivalent:  "h0-23", "h*-23",
  980. X"h0-*", "h*-*", "h*", "h0,1,2-10 h11-*".
  981. X.PP
  982. XThe tty accessibility class is composed of one or more string segments,
  983. Xone of which must match the tail of the current tty's name.  As with the
  984. Xnumeric accessibility classes, "-,!^*@" are all supported.
  985. X.PP
  986. XThe first entry in the control file, in which the current user's name is
  987. Xmatched within the "userspec", will be the entry processed for that
  988. Xuser.  The "userspec" is composed of one or more full usernames, one of
  989. Xwhich must exactly match the current user's name.  As with the numeric
  990. Xand tty accessibility classes, ",!^*@" are all supported.  Note that
  991. Xranges specified by `-' are NOT supported in the "userspec".
  992. X.SH EXAMPLES
  993. Xjoe h9-17 /bin/csh
  994. X.IP "" 5
  995. XAllow `joe' access only between 9AM and 5PM.
  996. X.PP
  997. Xuucp,net ttya7 w1-5 h*,!9-17 or ttya0-ab w0,6
  998. X.br
  999. X    /usr/lib/uucp/uucico
  1000. X.IP "" 5
  1001. XAllow `uucp' and `net' access on (/dev/t)tya7 weekdays except between
  1002. X9AM and 5PM
  1003. X.B or
  1004. Xon (/dev/t)tya0 thru (/dev/tty)ab (anytime) on weekends.  Note the "*"
  1005. Xis required in the hour specification.  Otherwise, since "h" appeared -
  1006. Xhours would be constrained, no unrestricted hours specified, then
  1007. Xfurther constrained to not be between 9 and 17.  In other words no hour
  1008. Xwould be acceptable and only the second accessibility constraint could
  1009. Xpossibly pass.
  1010. X.PP
  1011. X*,!root Y*-87 t*,!console or M*-9 Y88 t*,!console /bin/sh
  1012. X.IP "" 5
  1013. XAllow everyone access except `root' thru September 1988 on any tty
  1014. Xexcept consoles.  Note that if
  1015. X.I access
  1016. Xis specified as `root's login shell as this example implies, then `root'
  1017. Xmust have an entry somewhere following this example entry.  Alternately,
  1018. X`root' may have an entry before this one in which event the ",!root"
  1019. Xwould be extraneous since
  1020. X.I access
  1021. Xwould never get this far for user `root'.
  1022. X.PP
  1023. Xuucp /usr/lib/uucp/uucico
  1024. X.br
  1025. X*    /bin/csh
  1026. X.IP "" 5
  1027. XGive `uucp' unrestricted access to `uucico' and everyone else
  1028. Xunrestricted access to the `csh'.  Effectively,
  1029. X.I access
  1030. Xwould not be doing anything.  This would be one method of removing
  1031. Xaccess constraints for everyone without changing the password file.
  1032. X.SH TESTING
  1033. XIf
  1034. X.I access
  1035. Xis invoked from a shell then the access constraints will be derived from
  1036. Xits arguments (do not specify the `userspec').  In place of actually
  1037. Xexecuting the real login shell specified, that program's name and its
  1038. Xargument vector will be displayed.
  1039. X.SH INSTALLATION
  1040. XBe sure to disable users ability to change their login shell and thereby
  1041. Xdefeat this control.  For example, "chmod o-x /usr/ucb/chsh".
  1042. X.SH "SEE ALSO"
  1043. XFiles:  /etc/passwd and /usr/local/lib/access
  1044. X.SH DIAGNOSTICS
  1045. XIf at least one accessibility constraint passes, the presence of
  1046. X.I access
  1047. Xis invisible.  If no accessibility constraint passes, then a message is
  1048. Xissued and the user immediately logged off.
  1049. X.SH AUTHOR
  1050. XGeorge M. Sipe currently (7/88) at rebel!george
  1051. SHAR_EOF
  1052. fi
  1053. exit 0
  1054. #    End of shell archive
  1055. -- 
  1056. George M. Sipe,        Phone: (404) 662-1533
  1057. Tolerant Systems, 6961 Peachtree Industrial, Norcross, GA  30071
  1058. UUCP: ...!{decvax,hplabs,linus,rutgers,seismo}!gatech!rebel!george
  1059.